package com.hp.bon.sgw.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
import java.lang.management.LockInfo;
import java.lang.management.ManagementFactory;
import java.lang.management.MonitorInfo;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.ws.BindingProvider;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.STAXEventReader;
import org.dom4j.io.XMLWriter;

import cn.chinatelecom.sgw.soap.SGWService;
import cn.chinatelecom.sgw.soap.SGWService_Service;

import com.google.gson.Gson;
import com.hp.bon.sgw.Constants;
import com.hp.bon.sgw.bean.BlockRequestBean;
import com.hp.bon.sgw.bean.SysParamBean;
import com.hp.bon.sgw.bean.XmlMessage;

public class Comutils {
	public static final String GEN_DATA_FORMAT = "yyyyMMddHHmm";
	public static final String EFF_TIME_FORMAT = "yyyyMMddHHmmss";
	private static DefaultXMLEventFilter xmlEventFilter = new DefaultXMLEventFilter();

	static XMLInputFactory inputFactory = XMLInputFactory.newInstance();

	/**
	 * 利用StAXParser来解析XML，提高性能和效率
	 * 
	 * @param xmlContent
	 * @return Document
	 * @throws XMLStreamException
	 * @throws DocumentException
	 */
	public static Document parseText(String xmlContent) throws Exception {
		XMLEventReader xmlEventReader = inputFactory.createFilteredReader(inputFactory.createXMLEventReader(new StringReader(xmlContent)), xmlEventFilter);
		STAXEventReader reader = new STAXEventReader();
		Document result = reader.readDocument(xmlEventReader);
		return result;
	}

	/**
	 * 得到本机所有IP
	 * 
	 * @return
	 * @throws SocketException
	 */
	public static Set<String> getLocalhostAllIps() throws SocketException {
		Set<String> allIps = new LinkedHashSet<String>();
		Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
		InetAddress ip = null;
		while (allNetInterfaces.hasMoreElements()) {
			NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
			Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
			while (addresses.hasMoreElements()) {
				ip = addresses.nextElement();
				if (ip instanceof Inet4Address) {
					allIps.add(ip.getHostAddress());
				}
			}
		}
		allIps.add("localhost");
		return allIps;
	}

	public static String fixContentCharSet(String contentCharset) {
		if (contentCharset == null || contentCharset.length() == 0) {
			return "UTF-8";
		} else {
			if (contentCharset.startsWith("\"")) {
				contentCharset = contentCharset.substring(1, contentCharset.length() - 1);
				return contentCharset;
			} else {
				return contentCharset;
			}
		}
	}

	/**
	 * 从XML节点中找目标节点（叶子节点）的值，并填充
	 * 
	 * @param elment
	 * @param nodeNameSet
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static Map<String, String> getLeafNodeOfXMl(Element elment, Set<String> nodeNameSet) {
		Map<String, String> resulMap = new HashMap<String, String>(nodeNameSet.size());
		List<Element> allEls = (List<Element>) elment.selectNodes("//*[count(*)=0]");
		for (Element el : allEls) {
			if (el.hasContent()) {
				if (nodeNameSet.contains(el.getName())) {
					resulMap.put(el.getName(), el.getTextTrim());
				}
			}
		}
		return resulMap;
	}

	/**
	 * 返回一个符号SGWService 接口的WS client,
	 * 
	 * @param serverURL
	 *            server 的WS访问地址
	 * @return SGWService
	 */
	public static SGWService getSGWServiceClient(String serverURL) {
		URL wsdlURL;
		QName serviceQname = new QName("http://www.chinatelecom.cn/SGW/SOAP", "SGWService");
		String wsdl = "All_SGW_WEBSERVICE.wsdl";
		try {
			wsdlURL = Thread.currentThread().getContextClassLoader().getResource(wsdl);
			if (wsdlURL == null) {
				throw new RuntimeException("cant' find wsdl file " + wsdl);
			}
		} catch (Exception e) {
			throw new RuntimeException("bad wsdl url:" + e);
		}
		SGWService_Service sgwServiceClient = new SGWService_Service(wsdlURL, serviceQname);
		SGWService client = sgwServiceClient.getSGWServiceSOAP();
		Map<String, Object> ctx = ((BindingProvider) client).getRequestContext();
		ctx.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, serverURL);
		// ctx.put(BindingProviderProperties.REQUEST_TIMEOUT, 30000);
		// ctx.put(BindingProviderProperties.CONNECT_TIMEOUT, 10000);

		return client;
	}

	public static Properties getPropertiesFromFile(String file) {
		FileInputStream inStrem = null;
		try {
			Properties property = new Properties();
			inStrem = new FileInputStream(file);
			property.load(inStrem);
			return property;
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			if (inStrem != null) {
				try {
					inStrem.close();
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
		}

	}

	public static Properties getPropertiesFromFileNoThrow(String file) {
		FileInputStream inStrem = null;
		Properties property = new Properties();
		try {
			inStrem = new FileInputStream(file);
			property.load(inStrem);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (inStrem != null) {
				try {
					inStrem.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return property;

	}

	public static long parseStringTime(String dateStr, String format) throws ParseException {
		if (dateStr == null || dateStr.trim().length() == 0) {
			return 0;
		}
		Date date = new SimpleDateFormat(format).parse(dateStr);
		return date.getTime();
	}

	public static Map<String, String> parseArgs(String[] args) {
		String argLine = "";
		for (String arg : args) {
			argLine = argLine + " " + arg;
		}
		HashMap<String, String> map = new HashMap<String, String>();
		String[] pairs = argLine.split(" ");
		for (String pair : pairs) {
			int pos = pair.indexOf("=");
			String param = pair;
			String value = null;
			if (pos > 0) {
				param = pair.substring(0, pos);
				value = pair.substring(pos + 1);
				map.put(param, value);
			}

		}
		return map;
	}

	public static String formatTime(long time, String format) {
		return new SimpleDateFormat(format).format(new Date(time));
	}

	public static String formatTime(Date time, String format) {
		if (time != null) {
			return new SimpleDateFormat(format).format(time);
		} else {
			return null;
		}

	}

	public static String timeToSpanDay(long diff) {
		final long nd = 1000 * 24 * 60 * 60;// 一天的毫秒数
		final long nh = 1000 * 60 * 60;// 一小时的毫秒数
		final long nm = 1000 * 60;// 一分钟的毫秒数
		final long ns = 1000;// 一秒钟的毫秒数
		long day = diff / nd;// 计算差多少天
		long hour = diff % nd / nh;// 计算差多少小时
		long min = diff % nd % nh / nm;// 计算差多少分钟
		long sec = diff % nd % nh % nm / ns;// 计算差多少秒
		return new StringBuilder().append(day).append(" days ").append(hour).append(" hours ").append(min).append(" mins ").append(sec).append(" sec ").toString();
	}

	public static Map<String, BlockRequestBean> loadDelayCapParams(File file) throws Exception {
		LineNumberReader reader = null;
		Map<String, BlockRequestBean> blockMap = new LinkedHashMap<String, BlockRequestBean>();
		try {
			reader = new LineNumberReader(new InputStreamReader(new BufferedInputStream(new FileInputStream(file)), "utf-8"));
			String line = null;
			while ((line = reader.readLine()) != null) {
				if (!"".equals(line.trim())) {
					BlockRequestBean blockBean = new Gson().fromJson(line, BlockRequestBean.class);
					if (blockBean.isEnable()) {
						blockMap.put(blockBean.getCapability() + blockBean.getHostId(), blockBean);
					}
				}
			}
			return blockMap;
		} finally {
			if (reader != null) {
				reader.close();
			}
		}
	}

	public static Map<String, SysParamBean> loadSysParams(File file) throws Exception {
		LineNumberReader reader = null;
		Map sysParamsMap = new LinkedHashMap();
		try {
			reader = new LineNumberReader(new InputStreamReader(new BufferedInputStream(new FileInputStream(file)), "utf-8"));
			String line = null;
			while ((line = reader.readLine()) != null) {
				if (!"".equals(line.trim())) {
					SysParamBean paramBean = (SysParamBean) new Gson().fromJson(line, SysParamBean.class);
					sysParamsMap.put(paramBean.getName(), paramBean);
				}
			}
			return sysParamsMap;
		} finally {
			if (reader != null)
				reader.close();
		}
	}

	/**
	 * param key=value key=value
	 * 
	 * @param paramStr
	 * @return
	 */
	public static Map<String, String> parseSysParamStr(String paramStr) {
		Map<String, String> params = new LinkedHashMap<String, String>();
		String[] paris = paramStr.trim().split("\\s+");
		for (String pairValue : paris) {
			String[] items = pairValue.split("=");
			if (items.length != 2) {
				throw new RuntimeException("invalid :" + pairValue + " must obey 'key=value' form,no extra space char!");
			}
			params.put(items[0], items[1]);
		}
		return params;
	}

	public static void saveSysParams(Map<String, SysParamBean> newSysparamsMap, File file) throws IOException {
		Writer writer = null;
		Gson gson = new Gson();
		try {
			writer = new BufferedWriter(new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(file)), "utf-8"));
			for (SysParamBean paramBean : newSysparamsMap.values()) {
				writer.write(gson.toJson(paramBean));
				writer.write("\r\n");
			}
		} finally {
			if (writer != null)
				writer.close();
		}
	}

	public static void saveToFile(byte[] data, String fileName) throws IOException {
		BufferedOutputStream writer = null;
		try {
			writer = new BufferedOutputStream(new FileOutputStream(fileName));
			writer.write(data);
		} finally {
			if (writer != null) {
				writer.close();
			}
		}
	}

	public static Map<String, SysParamBean> validateSysParams(Map<String, SysParamBean> sysParamsMap) {
		Map resultMap = new HashMap();
		for (SysParamBean paramBean : sysParamsMap.values()) {
			if (!paramBean.validate()) {
				resultMap.put(paramBean.getName(), paramBean);
			}
		}

		return resultMap;
	}

	public static Calendar getStartTimeOfDay(long time) {
		Calendar c = Calendar.getInstance();
		// c.setTimeInMillis(time);
		c.set(Calendar.HOUR_OF_DAY, 0);
		c.set(Calendar.MINUTE, 0);
		c.set(Calendar.SECOND, 0);
		c.set(Calendar.MILLISECOND, 0);
		return c;
	}

	public static Calendar getEndTimeOfDay(long time) {
		Calendar c = Calendar.getInstance();
		c.setTimeInMillis(time);
		c.set(Calendar.HOUR_OF_DAY, 23);
		c.set(Calendar.MINUTE, 59);
		c.set(Calendar.SECOND, 59);
		c.set(Calendar.MILLISECOND, 999);
		return c;
	}

	public static long getStartTimeOfDay(Calendar c) {
		c.set(Calendar.HOUR_OF_DAY, 0);
		c.set(Calendar.MINUTE, 0);
		c.set(Calendar.SECOND, 0);
		c.set(Calendar.MILLISECOND, 0);
		return c.getTimeInMillis();
	}

	public static long getEndTimeOfDay(Calendar c) {
		c.set(Calendar.HOUR_OF_DAY, 23);
		c.set(Calendar.MINUTE, 59);
		c.set(Calendar.SECOND, 59);
		c.set(Calendar.MILLISECOND, 999);
		return c.getTimeInMillis();
	}

	public static void printSystemInfo() {
		// 在 Java 这个多线程的系统中，对线程的监控是相当重要的。ThreadMXBean 就是起到这个作用。
		// ThreadMXBean 可以提供的信息包括各个线程的各种状态，CPU 占用情况，以及整个系统中的线
		// 程状况。从 ThreadMXBean 可以得到某一个线程的 ThreadInfo 对象。这个对象中则包含了这个
		// 线程的所有信息。
		// 线程的信息
		ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
		// 所有的线程的编号
		long[] threadIds = threadMXBean.getAllThreadIds();
		for (long threadId : threadIds) {
			// 线程的信息
			ThreadInfo threadInfo = threadMXBean.getThreadInfo(threadId);
			System.out.println(threadInfo.toString());
			for (StackTraceElement stack : threadInfo.getStackTrace()) {
				System.out.println("   " + stack.getClassName() + " at " + stack.getMethodName() + " line:" + stack.getLineNumber());
			}
			// 线程被阻塞的数量
			System.out.println("blocked:" + threadInfo.getBlockedCount());
			// 被锁定线程的监控信息
			MonitorInfo[] monitorInfos = threadInfo.getLockedMonitors();
			for (MonitorInfo monitorInfo : monitorInfos) {
				int depth = monitorInfo.getLockedStackDepth();
				System.out.println("lock depth：" + depth);
			}
			// 异步锁定的信息
			LockInfo[] lockinfos = threadInfo.getLockedSynchronizers();
			// 锁定的信息
			for (LockInfo lockInfo : lockinfos) {
				System.out.println("lock name：" + lockInfo.getClassName());
			}
			// 线程的名称
			String threadName = threadInfo.getThreadName();
			System.out.println("thread name：" + threadName);
			Thread.State state = threadInfo.getThreadState();
			System.out.println("thread statname：" + state.name());

		}
		long threadCounts = threadMXBean.getThreadCount();
		System.out.println("live total：" + threadCounts);
		long totalThreadCount = threadMXBean.getTotalStartedThreadCount();
		System.out.println("total thread：" + totalThreadCount);

	}

	/**
	 * 补0
	 * 
	 * @param num
	 * @param length
	 * @return
	 */
	public static String getFamNum(int num, int length) {
		String numstr = num + "";
		for (int i = numstr.length(); i < length; i++) {
			numstr = "0" + numstr;
		}
		return numstr;
	}

	public static XmlMessage tuxedoXml2SgwQueryReq(String xml_str, String[] errcd_and_desc) throws Exception {
		errcd_and_desc[0] = "";
		errcd_and_desc[1] = "";
		XmlMessage req = new XmlMessage(true);
		org.dom4j.Document document = Comutils.parseText(xml_str);
		Element root = document.getRootElement();
		int err_no_tag = 0;
		int err_empty = 0;
		String mid = root.elementTextTrim("MID");
		if (mid == null) {
			++err_no_tag;
			errcd_and_desc[1] += "missing tag MID. ";
		} else {
			if (mid.length() == 0) { // MID(session_id) can not be empty
				++err_empty;
				errcd_and_desc[1] += "empty MID. ";
			} else {
				req.setMID(mid);
			}
		}

		String uid = root.elementTextTrim("UID");
		if (uid == null) {
			++err_no_tag;
			errcd_and_desc[1] += "missing tag UID. ";
		} else {
			req.setUID(uid);
		}

		String pwd = root.elementTextTrim("PWD");
		if (pwd == null) {
			++err_no_tag;
			errcd_and_desc[1] += "missing tag PWD. ";
		} else {
			req.setPWD(pwd);
		}

		String scid = root.elementTextTrim("SCID");
		if (scid == null) {
			++err_no_tag;
			errcd_and_desc[1] += "missing tag SCID. ";
		} else {
			if (scid.length() == 0) { // SCID can not be empty
				++err_empty;
				errcd_and_desc[1] += "empty SCID. ";
			} else {
				req.setSCID(scid);
			}
		}

		String sig = root.elementTextTrim("SIG");
		if (sig == null) {
			++err_no_tag;
			errcd_and_desc[1] += "missing tag SIG. ";
		} else {
			req.setSIG(sig);
		}

		Element dataEl = root.element("DATA");
		if (dataEl == null) {
			++err_no_tag;
			errcd_and_desc[1] += "missing tag DATA. ";
		} else {
			Element data = (Element) dataEl.elements().get(0);
			req.setDataElement(data);
			req.setDATA(data.asXML());
		}

		if (err_no_tag > 0 || err_empty > 0) {
			if (err_empty > 0)
				errcd_and_desc[0] = Constants.ResultCode.VALUE_ERROR + "";
			if (err_no_tag > 0)
				errcd_and_desc[0] = Constants.ResultCode.MISSING_TAG + "";
			return null;
		} else {
			return req;
		}
	}

	public static String genTuxedoRspsXmlStr(String sig, String rc, String ds, String data) {
		StringBuilder sb = new StringBuilder();
		// sb.append("HTTP/1.1 200 OK\r\n");
		// sb.append("Content-type: text/plain\r\n\r\n");
		sb.append("<SgwTuxedoSvc>\r\n");
		sb.append(String.format("<RTT>%s</RTT>\r\n", formatTime(System.currentTimeMillis(), EFF_TIME_FORMAT)));

		if (sig == null)
			sig = "";
		sb.append(String.format("<SIG>%s</SIG>\r\n", rc));

		if (rc == null)
			rc = "";
		sb.append(String.format("<RC>%s</RC>\r\n", rc));

		if (ds == null)
			ds = "";
		sb.append(String.format("<DS>%s</DS>\r\n", ds));

		if (data == null || data.length() == 0) {
			sb.append("<DATA></DATA>\r\n");
		} else {
			sb.append("<DATA>\r\n");
			sb.append(data);
			sb.append("</DATA>\r\n");
		}
		sb.append("</SgwTuxedoSvc>\r\n");
		return sb.substring(0);
	}

	/**
	 * 
	 * 将Clob转成String ,静态方法
	 * 
	 * @param clob
	 *            字段
	 * @return 内容字串，如果出现错误，返回 null
	 */

	public static String clobToString(javax.sql.rowset.serial.SerialClob clob) {
		if (clob == null)
			return null;
		StringBuffer sb = new StringBuffer(65535);// 64K
		Reader clobStream = null;
		try {
			clobStream = clob.getCharacterStream();
			char[] b = new char[60000];// 每次获取60K
			int i = 0;
			while ((i = clobStream.read(b)) != -1) {
				sb.append(b, 0, i);
			}
		} catch (Exception ex) {
			sb = null;
		} finally {
			try {
				if (clobStream != null) {
					clobStream.close();
				}
			} catch (Exception e) {

			}
		}
		if (sb == null)
			return null;
		else
			return sb.toString();
	}

	/**
	 * 将InputStream转换成某种字符编码的String
	 * 
	 * @param in
	 * @param encoding
	 * @return
	 * @throws Exception
	 */
	public static String InputStreamTOString(InputStream in, String encoding) throws Exception {

		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		byte[] data = new byte[1024];
		int count = -1;
		while ((count = in.read(data, 0, 1024)) != -1)
			outStream.write(data, 0, count);

		data = null;
		return new String(outStream.toByteArray(), encoding);
	}

	/**
	 * 
	 * 将String转成Clob ,静态方法
	 * 
	 * @param str
	 *            字段
	 * @return clob对象，如果出现错误，返回 null
	 */
	public static javax.sql.rowset.serial.SerialClob stringToClob(String str) {
		if (null == str)
			return null;
		else {
			try {
				return new javax.sql.rowset.serial.SerialClob(str.toCharArray());
			} catch (Exception e) {
				return null;
			}
		}
	}

	/**
	 * 采用UTF-8编码对Element进行输出
	 * 
	 * @param xmlDoc
	 * @return
	 * @throws IOException
	 */
	public static String asXML(org.dom4j.Element xmlDoc) {
		ByteArrayOutputStream byteRep = new ByteArrayOutputStream();
		OutputFormat format = OutputFormat.createPrettyPrint();// 缩减型格式
		// OutputFormat format = OutputFormat.createCompactFormat();//紧凑型格式
		format.setEncoding("UTF-8");// 设置编码
		XMLWriter xw;
		try {
			xw = new XMLWriter(byteRep, format);
			xw.write(xmlDoc);
			System.out.println("str:" + byteRep.toString());
			return byteRep.toString();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

	}

	  public static String datafileFormat()
	  {
	    int minute = Calendar.getInstance().get(12);
	    int mm = minute / 5 * 5;
	    String _mm = getFamNum(mm, 2);
	    return formatTime(System.currentTimeMillis(), "yyyyMMddHH") + _mm;
	  }
}